package cn.edu.jxau.framework.dao.core;

import cn.edu.jxau.framework.dao.cache.CacheKey;
import cn.edu.jxau.framework.dao.cache.LocalCache;
import cn.edu.jxau.framework.dao.exception.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mysql.jdbc.Statement;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Session<T> extends BaseSqlClass{
	private Logger logger = LoggerFactory.getLogger(Session.class);
	protected LocalCache localCache;
	private  SqlParser sqlParser = new SqlParser();;
	private ViewConstructor viewConstructor = new ViewConstructor();
	
	public boolean execute(String viewName, final Map<String, Object> params,List<HashMap<String, Object>> data) throws ConfigurationException {
		String method = sqlParser.getMethod(viewName);
		boolean flag = false;
		if(method.equals("insert")){
			flag = insert(viewName, params,data);
		}else if(method.equals("update")){
			flag = update(viewName, params);
		}else if(method.equals("delete")){
			flag = delete(viewName, params);
		}else if(method.equals("select")){
			List<HashMap<String, Object>> datas = select(viewName, params);
		    for(int i=0;i<datas.size();i++){
		        HashMap<String, Object> map = datas.get(i);	       
                data.add(map); 
		    }
		    flag = true;
		}else{
			throw new ConfigurationException("方法名错误");
		}
		/*if(getAutoCommit()){
		    releaseConnection();  //会话结束释放链接,在自动提交情况下，不开启事务，开启事务在外界手动释放
		}*/
		return flag;
	}
	Session(String id){
		localCache = new LocalCache(id);
	}
	
	private boolean insert(String viewName, final Map<String, Object> params,List<HashMap<String, Object>> data){
		
		List<Object> param = new ArrayList<>();
		String sql = sqlParser.parseInsertSql(viewName, params, param);
		System.out.println(sql);
		logger.debug(sql);
		PreparedStatement pstmt = null;
		boolean flag = false;
		ResultSet rs = null; 
		HashMap<String, Object> map = new HashMap<>();
		int id = 0; 
		try {
			pstmt = (PreparedStatement) conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
			jdbcUtils.initParameter(pstmt, param);
			flag = pstmt.executeUpdate() > 0 ? true : false;
			rs = pstmt.getGeneratedKeys();

	        if (rs.next()) 
	            id = rs.getInt(1); 
	
	        map.put("primary", id);
		} catch (SQLException e) {
			if(!getAutoCommit()){   //手动提交
				rollback();
			}
			e.printStackTrace();
		}finally{
			if(getAutoCommit()){
				clearCache();
			}
		}
		
		data.add(map);
        
		return flag;
		
	}
	
	private boolean update(String viewName, final Map<String, Object> params){
		
		List<Object> param = new ArrayList<>();
		String sql = sqlParser.parseUpdateSql(viewName, params, param);
		logger.debug(sql);
		System.out.println(param);
		PreparedStatement pstmt = null;
		boolean flag = false;
		try {
			pstmt = (PreparedStatement) conn.prepareStatement(sql);
			jdbcUtils.initParameter(pstmt, param);
			flag = pstmt.executeUpdate() > 0 ? true : false;
		} catch (SQLException e) {
			if(!getAutoCommit()){   //手动提交
				rollback();
			}
			e.printStackTrace();
		}finally{
			if(getAutoCommit()){
				clearCache();
			}
		}
		return flag;
	}
	
	private boolean delete(String viewName, final Map<String, Object> params){
		
		List<Object> param = new ArrayList<>();
		String sql = sqlParser.parseDeleteSql(viewName, params, param);
		logger.debug(sql);
		System.out.println(param);
		PreparedStatement pstmt = null;
		boolean flag = false;
		try {
			pstmt = (PreparedStatement) conn.prepareStatement(sql);
			jdbcUtils.initParameter(pstmt, param);
			flag = pstmt.executeUpdate() > 0 ? true : false;
		} catch (SQLException e) {
			if(!getAutoCommit()){   //手动提交
				rollback();
			}
			e.printStackTrace();
		}finally{
			if(getAutoCommit()){
				clearCache();
			}
		}
		return flag;
	}
	
	private List<HashMap<String, Object>> select(String viewName, final Map<String, Object> params){
		
		List<Object> param = new ArrayList<>();
		String sql = sqlParser.parseSelectSql(viewName, params, param);
		logger.debug(sql);
		sql = sql.trim();
	
		//*****************缓存查询*************************/

		CacheKey cacheKey = new CacheKey(sql, param);
		List<HashMap<String, Object>> cacheReulst = localCache.getObject(cacheKey);
		if (cacheReulst != null) {
			return (List<HashMap<String, Object>>) cacheReulst;
		}
		
		PreparedStatement pstmt = null;
		ResultSet relust = null;
		
		try {
			pstmt = (PreparedStatement) conn.prepareStatement(sql);
			jdbcUtils.initParameter(pstmt, param);
			relust =  pstmt.executeQuery();
		} catch (SQLException e) {
			if(!getAutoCommit()){   //手动提交
				rollback();
			}
			e.printStackTrace();
		}
		
		
		HashMap<String, Integer> SQLRelustMapper = new HashMap<String, Integer>();
		ResultSetMetaData rsmd;
		try {
			rsmd =  relust.getMetaData();
			int numCols = rsmd.getColumnCount(); 
			for(int i=1;i<=numCols;i++){
				String ColumnLabel = rsmd.getColumnLabel(i);
				
				String name = rsmd.getColumnName(i);
				if(SQLRelustMapper.get(ColumnLabel)!=null){
					String tableName = rsmd.getTableName(i);
					SQLRelustMapper.put(tableName+"."+ColumnLabel,i);
				}else{
					SQLRelustMapper.put(ColumnLabel,i);
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		List<HashMap<String, Object>> listRelust = new ArrayList();
		try {
			while(relust.next()){
				listRelust.add((HashMap<String, Object>) viewConstructor.ConstructView(relust, SQLRelustMapper));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		/**************缓存存储***********/
		localCache.putObject(cacheKey, listRelust);
		
		return listRelust;
	}
	
	private LocalCache getLocalCache() {
		return localCache;
	}
	
	private void clearCache(){
		localCache.clear();
	}
	
	public boolean commmit(){
		//提交事务

		try {
			conn.commit();
			clearCache();
		} catch (SQLException e) {
			rollback();
			e.printStackTrace();
		}
		return false;
		
	}
}
